package gitee.derumin.lib_for_derumin.commands;

import com.google.gson.*;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.tree.LiteralCommandNode;
import gitee.derumin.lib_for_derumin.commands.suggestionproviders.ConfigElementSuggestionProvider;
import gitee.derumin.lib_for_derumin.commands.suggestionproviders.ConfigEntrySuggestionProvider;
import gitee.derumin.lib_for_derumin.commands.suggestionproviders.ConfigNameSuggestionProvider;
import gitee.derumin.lib_for_derumin.commands.suggestionproviders.PlayerNameSuggestionProvider;
import gitee.derumin.lib_for_derumin.helpers.config.ConfigHelper;
import gitee.derumin.lib_for_derumin.logger.DeruminLogger;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Text;

import java.util.List;

public class ConfigCommand {
    private static final DeruminLogger LOGGER = DeruminLogger.getLogger();

    public static void register(){
        CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
            final int re = environment.dedicated? 2 : 0;
            final LiteralCommandNode<ServerCommandSource> dch = dispatcher.register(CommandManager.literal("deruminconfighelper")
                    .requires(serverCommandSource -> serverCommandSource.hasPermissionLevel(re))
                    .then(CommandManager.literal("list")
                            .executes(context -> {
                                List<String> names = ConfigHelper.getConfigNames();
                                for (String name : names){
                                    context.getSource().sendFeedback(() -> Text.of(name), false);
                                }
                                return names.size();}))
                    .then(CommandManager.literal("get")
                            .then(CommandManager.argument("configname", StringArgumentType.string())
                                    .suggests(ConfigNameSuggestionProvider.PROVIDER)
                                    .executes(context -> {
                                        JsonObject object = ConfigHelper.getConfigByName(StringArgumentType.getString(context, "configname"), false);
                                        if (object == null){
                                            return -1;
                                        }
                                        context.getSource().sendFeedback(() -> Text.of(new GsonBuilder().setPrettyPrinting().create().toJson(object)), false);
                                        return 1;})
                                    .then(CommandManager.argument("entry", StringArgumentType.string())
                                            .suggests(ConfigEntrySuggestionProvider.PROVIDER)
                                            .executes(context -> {
                                                JsonObject object = ConfigHelper.getConfigByName(StringArgumentType.getString(context, "configname"),  false);
                                                String name = StringArgumentType.getString(context, "entry");
                                                if (object != null && object.has(name)) {
                                                    JsonElement element = object.get(name);
                                                    String  contains;
                                                    try {
                                                        contains = element.getAsString();
                                                    }catch (Exception e){
                                                        contains = element.toString();
                                                    }
                                                    String finalContains = contains;
                                                    context.getSource().sendFeedback(() -> Text.of(finalContains), false);
                                                    return 1;
                                                }else {
                                                    context.getSource().sendFeedback(() -> Text.of("No such config."), false);
                                                    return -1;
                                                }}))))
                    .then(CommandManager.literal("modify")
                            .then(CommandManager.argument("configname", StringArgumentType.string())
                                    .suggests(ConfigNameSuggestionProvider.PROVIDER)
                                    .then(CommandManager.argument("entry", StringArgumentType.string())
                                            .suggests(ConfigEntrySuggestionProvider.PROVIDER)
                                            .then(CommandManager.argument("argument", StringArgumentType.string())
                                                    .suggests(ConfigElementSuggestionProvider.PROVIDER)
                                                    .executes(context -> {
                                                        LOGGER.info("[Derumin Config Command]" + context.getSource().getName() + "tried to modify config with input:" + context.getInput(), DeruminLogger.AnnounceType.OPS);
                                                        JsonObject object = new JsonObject();
                                                        String input = StringArgumentType.getString(context, "argument");
                                                        JsonElement element;
                                                        try {
                                                            element = JsonParser.parseString(input);
                                                        }catch (Exception e){
                                                            element = new JsonPrimitive(input);
                                                        }
                                                        object.add(StringArgumentType.getString(context, "entry"), element);
                                                        if (ConfigHelper.modifyConfigByName(StringArgumentType.getString(context, "configname"), object)){
                                                            context.getSource().sendFeedback(() -> Text.of("Modified a config entry."), false);
                                                            return 1;
                                                        }else {
                                                            context.getSource().sendFeedback(() -> Text.of("Failed. There's no such entry or the input is not the same type with the entry, or the modification is refused."), false);
                                                            return -1;}})))))
                    .then(CommandManager.literal("reset")
                            .then(CommandManager.argument("configname", StringArgumentType.string())
                                    .suggests(ConfigNameSuggestionProvider.PROVIDER)
                                    .executes(context -> {
                                                String config = StringArgumentType.getString(context, "configname");
                                                LOGGER.info("[Derumin Config Command]" + context.getSource().getName() + "tried to reset config:" + config, DeruminLogger.AnnounceType.OPS);
                                                if (ConfigHelper.resetConfigByName(config)){
                                                    context.getSource().sendFeedback(() -> Text.of("Tried to reset the targeted config."), false);
                                                    return 1;
                                                }else {
                                                    return -1;}})
                                    .then(CommandManager.argument("entry", StringArgumentType.string())
                                            .suggests(ConfigEntrySuggestionProvider.PROVIDER)
                                            .executes(context -> {
                                                String config = StringArgumentType.getString(context, "configname");
                                                JsonObject defaultJson = ConfigHelper.getDefaultConfigJson(config);
                                                String name = StringArgumentType.getString(context, "entry");
                                                LOGGER.info("[Derumin Config Command]" + context.getSource().getName() + "tried to reset config entry:" + name + " in " + config , DeruminLogger.AnnounceType.OPS);
                                                if (defaultJson != null && defaultJson.has(name)) {
                                                    JsonObject newJson = new JsonObject();
                                                    newJson.add(name, defaultJson.get(name));
                                                    ConfigHelper.modifyConfigByName(config, newJson);
                                                    context.getSource().sendFeedback(() -> Text.of("Tried to reset the targeted config."), false);
                                                    return 1;
                                                }else {
                                                    context.getSource().sendFeedback(() -> Text.of("No such config."), false);
                                                    return -1;
                                                }}))))
                    .then(CommandManager.literal("reload")
                            .then(CommandManager.argument("configname", StringArgumentType.string())
                                    .suggests(ConfigNameSuggestionProvider.PROVIDER)
                                    .executes(context -> {
                                                String config = StringArgumentType.getString(context, "configname");
                                        LOGGER.info("[Derumin Config Command]" + context.getSource().getName() + "tried to reload config:" + config , DeruminLogger.AnnounceType.OPS);
                                                if (ConfigHelper.reloadConfigByName(config)){
                                                    context.getSource().sendFeedback(() -> Text.of("Tried to reload the targeted config."), false);
                                                    return 1;
                                                }else {
                                                    return -1;}})))
                    .then(CommandManager.literal("save")
                            .then(CommandManager.argument("configname", StringArgumentType.string())
                                    .suggests(ConfigNameSuggestionProvider.PROVIDER)
                                    .executes(context -> {
                                                if (ConfigHelper.saveConfigByName(StringArgumentType.getString(context, "configname"))){
                                                    context.getSource().sendFeedback(() -> Text.of("Tried to save the targeted config."), false);
                                                    return 1;
                                                }else {
                                                    return -1;}}))
                            .then(CommandManager.literal("all")
                                    .executes(
                                            context -> {
                                                ConfigHelper.saveAll();
                                                context.getSource().sendFeedback(() -> Text.of("Tried to save all configs."), false);
                                                return 1;})))
                    .then(CommandManager.literal("deleteconfigfile")
                            .then(CommandManager.argument("configname", StringArgumentType.string())
                                    .suggests(ConfigNameSuggestionProvider.PROVIDER)
                                    .executes(context -> ConfigHelper.deleteConfigFileByName(StringArgumentType.getString(context, "configname"))? 1 : -1)))
                    .then(CommandManager.literal("player")
                            .then(CommandManager.argument("playername", StringArgumentType.string())
                                    .suggests(PlayerNameSuggestionProvider.PROVIDER)
                                    .executes(context -> {
                                        context.getSource().sendFeedback(() -> Text.of("Not developed yet."), false);
                                        return 0;
                                    })
                            )
                    )
            );
            dispatcher.register(CommandManager.literal("dch").redirect(dch));
        });
    }
}
